home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).zip / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).adf / A68K_Docs / A68k.doc next >
Text File  |  1989-07-02  |  24KB  |  532 lines

  1.     A68k - a freely    distributable assembler    for the    Amiga
  2.  
  3.             by Charlie Gibbs
  4.  
  5.              with special thanks to
  6.         Brian R. Anderson and Jeff Lydiatt
  7.  
  8.          (Version 2.41 - January 6, 1989)
  9.  
  10.      Note:  This program is Freely-Distributable, as opposed to    Public
  11. Domain.     Permission is given to    freely distribute this program provided    no
  12. fee is charged,    and this documentation file is included    with the program.
  13.  
  14.      This assembler is based on    Brian R. Anderson's 68000 cross-
  15. assembler published in Dr. Dobb's Journal, April through June 1986.
  16. I have converted it to produce AmigaDOS-format object modules, and
  17. have made many enhancements, such as macros and    INCLUDE    files.
  18.  
  19.      My    first step was to convert the original Modula-2    code into C.
  20. I did this for two reasons.  First, I had access to a C    compiler, but
  21. not a Modula-2 compiler.  Second, I like C better anyway.
  22.  
  23.      The executable code generator code    (GetObjectCode and MergeModes)
  24. is essentially the same    as in the original article, aside from its
  25. translation into C.  I have almost completely rewritten    the remainder
  26. of the code, however, in order to remove restrictions, add enhancements,
  27. and adapt it to    the AmigaDOS environment.  Since the only reference book
  28. available to me    was the    AmigaDOS Developer's Manual (Bantam, February
  29. 1986), the assembler and the remainder of this document    work in    terms
  30. of that    book.
  31.  
  32.  
  33. RESTRICTIONS
  34.  
  35.      Let's get these out of the way first.  There are a few things that I
  36. have not yet implemented, and some outright bugs that would take too long
  37. to correct for this version.
  38.  
  39.       o    The verification file (-v) option is not supported.  Diagnostic
  40.     messages always    appear on the console.    They also appear in the
  41.     listing    file, however (see extensions below).  You can produce
  42.     an error file by redirecting console output to a file -    the
  43.     line number counter and    final summary are displayed on stderr
  44.     so you can still see what's happening.
  45.  
  46.       o    The file names in the INCLUDE directory    list (-i) must be separated
  47.     by commas.  The    list may not be    enclosed in quotes.
  48.  
  49.       o    Labels assigned    by EQUR    and REG    directives are case-sensitive.
  50.  
  51.       o    The following directives are not supported, and    will be    flagged    as
  52.     invalid    op-codes:
  53.  
  54.         OFFSET
  55.         NOPAGE
  56.         LLEN
  57.         PLEN
  58.         NOOBJ
  59.         FAIL
  60.         FORMAT
  61.         NOFORMAT
  62.         MASK2
  63.  
  64.     I feel that NOPAGE, LLEN, and PLEN should not be defined within    a
  65.     source module.    It doesn't make sense to me to have to change your
  66.     program    just because you want to print your listings on    different
  67.     paper.    The command-line option    "-p" (see below) can be used as a
  68.     replacement for    PLEN; setting it to a high value (like 32767) is a
  69.     good substitute    for NOPAGE.  The effect    of LLEN    can be obtained
  70.     by running the listing file through an appropriate filter.
  71.  
  72.  
  73. EXTENSIONS
  74.  
  75.      Now for the good stuff:
  76.  
  77.       o    Labels can be any length that will fit onto one    source line
  78.     (currently 127 bytes maximum).    Since labels are stored    on the
  79.     heap, the number of labels that    can be processed is limited only
  80.     by available memory.
  81.  
  82.       o    Since section data and user macro definitions are stored in the
  83.     symbol table (see above), they too are limited only by available
  84.     memory.     (Actually, there is a hard-coded limit    of 32767 sections,
  85.     but I doubt anyone will    run into that one.)
  86.  
  87.       o    The only values    a label    cannot take are    the register names - the
  88.     assembler can distinguish between the same name    used as    a label,
  89.     instruction name or directive, macro name, or section name.
  90.  
  91.       o    Section    and user macro names appear in the symbol table    dump, and
  92.     will also be cross-referenced.    Their names can    be the same as any
  93.     label (see above); the assembler can sort them out.
  94.  
  95.       o    INCLUDEs and macro calls can be    nested indefinitely, limited only
  96.     by available memory.  The message "Secondary heap overflow -
  97.     assembly terminated" will be displayed if memory is exhausted.
  98.     You can    increase the size of this heap using the -w parameter
  99.     (see below).  Recursive    macros are supported; recursive    INCLUDEs
  100.     will, of course, result    in a loop that will be broken only when
  101.     the heap overflows.
  102.  
  103.       o    The EVEN directive forces alignment on a word (2-byte) boundary.
  104.     It does    the same thing as CNOP 0,2.
  105.     (This one is left over from the    original code.)
  106.  
  107.       o    Branch (Bcc) instructions to a previously-defined label    will be
  108.     automatically converted    to short form if possible.  This feature is
  109.     not available for forward branches, since in pass 1 the    assembler
  110.     doesn't yet know how far the branch must go.  You can, however,
  111.     ask A68k to tell you which instructions    can be coded as    short
  112.     branches by using the -f command-line switch (see below).
  113.  
  114.       o    Backward references to labels within the current CODE section
  115.     will be    converted to PC    relative addressing with displacement
  116.     if this    mode is    legal for the instruction.
  117.  
  118.       o    If a MOVEM instruction only specifies one register, it is converted
  119.     to the corresponding MOVE instruction.    Instructions such as
  120.     MOVEM D0-D0,label will not be converted, however.
  121.  
  122.       o    ADD, SUB, and MOVE instructions    will be    converted to ADDQ, SUBQ,
  123.     and MOVEQ respectively if possible.  Instructions coded    explicitly
  124.     as (for    example) ADDA or ADDI will not be converted.
  125.  
  126.       o    ADD, CMP, SUB, and MOVE    to an address register are converted to
  127.     ADDA, CMPA, SUBA, and MOVEA respectively, unless (for ADD, SUB,
  128.     or MOVE) they have already been    converted to quick form.
  129.  
  130.       o    ADD, AND, CMP, EOR, OR,    and SUB    of an immediate    value are converted
  131.     to ADDI, ANDI, CMPI, EORI, ORI,    and SUBI respectively (unless the
  132.     address    register or quick conversion above has already been done).
  133.  
  134.       o    If both    operands of a CMP instruction are postincrement    mode, the
  135.     instruction is converted to CMPM.
  136.  
  137.       o    Operands of the    form 0(An) will    be treated as (An) except for
  138.     the MOVEP instruction, which always requires a displacement.
  139.  
  140.       o    The SECTION directive allows a third parameter.     This can be
  141.     specified as either CHIP or FAST (upper- or lower-case).  If this
  142.     parameter is present, the hunk will be written with the    MEMF_CHIP
  143.     or MEMF_FAST bit set.  This allows you to produce "pre-ATOMized"
  144.     object modules.
  145.  
  146.       o    The synonyms DATA and BSS are accepted for SECTION directives
  147.     starting data or BSS hunks.  The CHIP and FAST options mentioned
  148.     above can also be used,    e.g. BSS name,CHIP.
  149.  
  150.       o    The following synonyms have been implemented for compatibility
  151.     with the Aztec assembler:
  152.         CSEG is    treated    the same as CODE or SECTION name,CODE
  153.         DSEG is    treated    the same as DATA or SECTION name,DATA
  154.         PUBLIC is treated as either XDEF or XREF, depending on
  155.             whether or not the symbol in question has been
  156.             defined in the current source module.
  157.             A single PUBLIC directive can name a mixture
  158.             internally-    and externally-defined symbols.
  159.  
  160.       o    The ability to produce Motorola    S-records is retained from the
  161.     original code.    The -s option causes the assembler to produce
  162.     S-format instead of AmigaDOS format.  Relocatable code cannot be
  163.     produced in this format.
  164.  
  165.       o    Error messages consist of three    parts.
  166.         The    position of the    offending line is given    as a line number
  167.     within the current module.  If the line    is within a macro expan-
  168.     sion or    INCLUDE    file, the position of the macro    call or    INCLUDE
  169.     statement in the outer module is given as well.     This process
  170.     is repeated until the outermost    source module is reached.
  171.         Next, the offending    source line itself is listed.
  172.         Finally, the errors    for that line are displayed.  A    flag
  173.     (^) is placed under the    column where the error was detected.
  174.  
  175.       o    Named local labels are supported.  These work the same as the
  176.     local labels supported by the Metacomco    assembler (nnn$) but
  177.     can be formed in the same manner as normal labels, except that
  178.     the first character must be a backslash    (\).
  179.  
  180.       o    The following synonyms have been implemented for compatibility
  181.     with the Assempro assembler:
  182.         ENDIF is treated the same as ENDC
  183.         = is treated the same as EQU
  184.         | is treated the same as ! (logical OR)
  185.  
  186.       o    Quotation marks    (") can be used as string delimiters
  187.     as well    as apostrophes (').  Any given string must begin
  188.     and end    with the same delimiter.  This allows such statements
  189.     as the following:
  190.         MOVEQ    '"',D0
  191.         DC.B    "This is Charlie's assembler."
  192.     Note that you can still    define an apostrophe within a string
  193.     delimited by apostrophes if you    double it, e.g.
  194.         MOVEQ    '''',D0
  195.         DC.B    'This is Charlie''s assembler.'
  196.  
  197.       o    If any errors are found    in the assembly, the object code file
  198.     will be    scratched, unless you specified    the -k (keep) flag
  199.     on the command line.
  200.  
  201.       o    The symbols .A68K, .a68k, .a68K, and .A68k are automatically
  202.     defined    as SET symbols having absolute values of 1.
  203.     This enables a source program to determine whether it is
  204.     being assembled    by this    assembler, and is effectively
  205.     insensitive as to whether or not it is checked in upper    case.
  206.  
  207.       o    A zeroth positional macro parameter (\0) is supported.    It
  208.     is replaced by the length of the macro call (B,    W, or L,
  209.     defaulting to W).  For instance, given the macro:
  210.         moov    MACRO
  211.             move.\0    \1,\2
  212.             ENDM
  213.     the macro call
  214.             moov.l    d0,d1
  215.     would be expanded as
  216.             move.l    d0,d1
  217.  
  218.       o    If an INCLUDE file doesn't generate any code and no listing
  219.     file is    required (including suppression    of the listing using
  220.     NOLIST), it won't be read again in pass 2.  The statement
  221.     numbers    will be    bumped to keep in proper alignment.  This
  222.     can really speed up assemblies that INCLUDE lots of EQUates.
  223.  
  224.       o    The ORG    directive is supported.     It works like RORG, except
  225.     that it    takes the actual address to be jumped to, rather
  226.     than an    offset from the    start of the current section.
  227.     The given address must be in the current section.
  228.     As far as A68k is concerned, the only real difference
  229.     between    ORG and    RORG is    that the ORG value must    be
  230.     relocatable, while the RORG value must be absolute.
  231.  
  232.  
  233. THE SMALL CODE / SMALL DATA MODEL
  234.  
  235.      Version 2.4 implements a rudimentary small    code/data model.
  236. It consists of converting any data reference to    one of the following
  237. three addressing modes:
  238.     address    register indirect with displacement (using A4)
  239.         (for references    to the DATA or BSS section)
  240.     program    counter    indirect with displacement
  241.         (for references    to the CODE section)
  242.     absolute word
  243.         (for absolute and 16-bit relocatable values)
  244. These conversions do not take place unless a NEAR directive is
  245. encountered.  Any operands on the NEAR directive are ignored.
  246. Conversion is done for all operands until a FAR    directive is
  247. encountered.  NEAR and FAR directives can occur    any number of
  248. times, enabling    conversion to be turned    on and off at will.
  249.  
  250.      Backward references which cannot be converted (e.g. external
  251. labels declared    as XREF) will remain as    absolute long addressing.
  252. All forward references are assumed to be convertible, since during
  253. pass 1 A68k has    no way of telling whether conversion is    possible.
  254. If conversion turns out    to be impossible, invalid object code will
  255. be generated - an error    message    ("Invalid forward reference") will
  256. indicate when this occurs.
  257.  
  258.      Although the small    code/data model    can greatly reduce the
  259. size of    assembled programs, several restrictions apply:
  260.  
  261.       o    Small code and small data models are active simultaneously.
  262.     You can't have one without the other, since during pass 1
  263.     A68k doesn't know whether forward references are to CODE
  264.     or to DATA/BSS.
  265.  
  266.       o    Programs can consist of    a maximum of two sections,
  267.     one CODE, the other DATA or BSS.  If you try to    define
  268.     a third    section, the message "Too many SECTIONs" will
  269.     be displayed.  The NEAR    directive is active only within
  270.     the CODE section.
  271.  
  272.       o    While the NEAR directive is active, external labels (XREF)
  273.     must be    declared before    they are used, CODE section references
  274.     must be    with 32K of the    current    position (i.e. expressible as
  275.     PC-relative), and DATA/BSS section references must be in the
  276.     first 64K of the DATA/BSS section (i.e.    expressible as
  277.     address    register indirect with displacement).  Any instructions
  278.     which do not satisfy these requirements    cannot be detected in
  279.     pass 1,    so A68k    has no choice but to display an    error message
  280.     in pass    2 ("Invalid forward reference") which in this case
  281.     indicates that invalid code has    been generated.     To properly
  282.     assemble such instructions, you    can temporarily    disable
  283.     conversion with    a FAR directive, then resume afterwards
  284.     with another NEAR directive.
  285.  
  286.       o    Conversion cannot be done for references between modules.
  287.     All external references    must be    left as    absolute long.
  288.  
  289.       o    A68k assumes that register A4 points to    the start of the
  290.     DATA/BSS section plus 32768 bytes.  A4 must be preloaded
  291.     with this value    before executing any code converted by the
  292.     NEAR directive.     One way to do this is to code the instruction
  293.     that loads the register    prior to the NEAR directive.  Another
  294.     way is to use a    MOVE.L with immediate mode, which is never
  295.     converted.  Here are examples of the two methods:
  296.  
  297.         LEA    data+32768,a4        NEAR
  298.         NEAR                MOVE.L    #data+32768,a4
  299.         <remainder of code>            <remainder of code>
  300.         BSS                BSS
  301.     data:                data:
  302.         <data areas>            <data areas>
  303.         END                END
  304.  
  305.  
  306. HOW TO USE A68k
  307.  
  308.      The command-line syntax to    run the    assembler is as    follows:
  309.  
  310.     a68k <source file name>
  311.          [<object file name>]
  312.          [<listing file name>]
  313.         [-d]
  314.         [-e<equate file    name>]
  315.         [-f]
  316.         [-h<header file    name>]
  317.         [-i<INCLUDE directory list>]
  318.         [-k]
  319.         [-l<listing file name>]
  320.         [-o<object file>]
  321.         [-p<page depth>]
  322.         [-q[<quiet interval>]]
  323.         [-s]
  324.         [-t]
  325.         [-w[<hash table    size>][,<secondary heap    size>]]
  326.         [-x<listing file name>]
  327.         [-y]
  328.         [-z[<debug start line>][,<debug    end line>]]
  329.  
  330. These options can be given in any order, and the source    file name can
  331. appear before all switches, after them,    or anywhere in the middle.
  332. Option values, if any, must immediately    follow the keyword with
  333. no intervening spaces.
  334.  
  335.      If    the -o keyword is omitted, the object file will    be given a default
  336. name.  It is created by    replacing all characters after the last    period in
  337. the source file    name by    "o".  For example, if the source file name is
  338. "myprog.asm", the object file name defaults to "myprog.o".  A source name
  339. of "my.new.prog.asm" produces a default object file name of "my.new.prog.o".
  340. If the source file name    does not contain a period, ".o" is appended to it
  341. to produce the default object file name.
  342.  
  343.      The default value for the listing file name is arrived at in the same
  344. way as the object file name, except that ".lst" is appended instead of ".o".
  345. If you don't specify this parameter, no listing file will be produced.
  346. If you specify -x (see below), -l (with    the default name) is assumed,
  347. although you can still use this    parameter if you wish.
  348.  
  349.      The default value for the equate file name    is arrived at in the same
  350. way as the object file name, except that ".equ" is appended instead of ".o".
  351.  
  352.      The INCLUDE directory list    is a list of directory names separated by
  353. commas.     No embedded blanks are    allowed.  For example, the specification
  354.     -imylib,df1:another.lib
  355. will cause INCLUDE files to be searched    for first in the current directory,
  356. then in    "mylib", then in "df1:another.lib".
  357.  
  358.      The -d keyword causes symbol table    entries    (hunk_symbol) to be written
  359. to the object module for the use of symbolic debuggers.
  360.  
  361.      The -f keyword causes any forward branches    (Bcc, BRA, BSR)    that
  362. could be converted to short form to be flagged.     A68k can't convert them
  363. automatically because it doesn't know in pass 1 how far the branch will
  364. be.  This option tells you which instructions could be manually    converted.
  365.  
  366.      The -k keyword causes the object file to be kept if any errors were
  367. found.    Otherwise, it will be scratched    if any errors occurred.
  368.  
  369.      The -l keyword causes a listing file to be    produced.  If you want
  370. the listing file to include a symbol table dump    and cross-reference,
  371. use the    -x keyword instead (see    below).
  372.  
  373.      The -p keyword causes the page depth to be    set to the specified value.
  374. If omitted, a default of 60 lines (-p60) is assumed.
  375.  
  376.      The -q keyword changes the    interval at which A68k displays    the
  377. current    line number (the default is every 10 lines, i.e. -q10).     If
  378. you specify -q0    or -q without a    value, no line numbers will be displayed.
  379. This will speed    up assemblies slightly by reducing console I/O.     If -q
  380. is specified as    a negative number (e.g.    -q-10),    line numbers will still
  381. be displayed at    the specified interval,    but will be given as positions
  382. within the current module (source, macro, or INCLUDE) rather than
  383. as a total statement count - the module    name will also be displayed.
  384.  
  385.      The -s keyword, if    specified, causes the object file to be    written    in
  386. Motorola S-record format.  If omitted, AmigaDOS    format will be produced.
  387. The default name for an    S-record file has ".s" appended to the source name,
  388. rather than ".o"; this can still be overridden with the -o keyword, though.
  389.  
  390.      The -t keyword allows tabs    in the source file to be passed    through
  391. to the listing file, rather than being expanded.  In addition, tabs will
  392. be generated in    the listing file to skip from the object code to the
  393. source statement, etc.    This can greatly reduce    the size of the    listing
  394. file, as well as making    it quicker to produce.    Do not use this    option
  395. if you will be displaying or listing the list file on a    device which
  396. does not assume    a tab stop at every 8th    position.
  397.  
  398.      The -w keyword specifies the size of the fixed memory areas that
  399. are allocated.    The first parameter gives the number of    entries    that
  400. the hash table will contain (defaulting    to 2047).  This    should be enough
  401. for all    but the    very largest programs.    The assembly will not fail if
  402. this value is too small, but may slow down as a    result of A68k having
  403. to search many long hash chains.  I've heard that you should really
  404. specify    a prime    number for this    parameter, but I haven't gone into
  405. hashing    theory enough to know whether it's actually necessary.
  406.      The second    parameter of the -w keyword specifies the size of the
  407. secondary heap (defaulting to 1024 bytes, which    should be enough
  408. unless you use very deeply nested macros and/or    INCLUDE    files with long
  409. path names).
  410.      You can specify either or both parameters.     For example:
  411.     -w4093        secondary heap size remains at 1024 bytes
  412.     -w,2000        hash table size    remains    at 2047    entries
  413.     -w4093,2000    increases the size of both areas
  414.      If    you're really tight for memory, and are assembling small modules,
  415. you can    use this keyword to shrink these areas below their default sizes.
  416. At the end of an assembly, a message will be displayed giving the sizes
  417. actually used, in the form of the -w command you would have to enter to
  418. allocate that much space.  This    is primarily useful to see how much
  419. secondary heap space was used.
  420.      NOTE: All other table storage (e.g. the actual symbol table) is
  421. allocated as required (currently in 8K chunks).
  422.  
  423.      The -x keyword works the same as -l, except that a    symbol table
  424. dump, including    cross-reference    information, will be added to the end
  425. of the listing file.
  426.  
  427.      The -y keyword causes hashing statistics to be displayed.    First
  428. the number of symbols in the table is given, followed by a breakdown
  429. of hash    chains by length.  Chains with length zero denote unused hash
  430. table entries.    Ideally    (i.e. if there were no collisions) there should
  431. be as many chains with length 1    as there are symbols, and there    should
  432. be no chains of    length 2 or greater.  I    added this option to help me
  433. tune my    hashing    algorithm, but you can also use    it to see whether you
  434. should allocate    a larger hash table (using the first parameter of the
  435. -w option, see above).
  436.  
  437.      The -z keyword is provided    for debugging purposes.     You can cause
  438. the assembler to list a    range of source    lines, complete    with line number
  439. and current location counter value, during both    passes.     For example:
  440.     -z        lists all source lines
  441.     -z100,200    lists lines 100    through    200
  442.     -z100        lists all lines    starting at 100
  443.     -z,100        lists the first    100 lines
  444.  
  445.  
  446.      If    you wish to override the default object    and (optionally) listing
  447. file names, you    can omit the -o    and -l keywords.  The assembler    interprets
  448. the first three    parameters without leading hyphens as the source, object,
  449. and listing file names respectively.  Anything over three file names is    an
  450. error, as is attempting    to respecify a file name with the -o or    -l keywords.
  451.  
  452.  
  453. TECHNICAL INFORMATION
  454.  
  455.      The actual    symbol table entries (pointed to by the    hash table,
  456. colliding entries are linked together) are stored in 8K    chunks which
  457. are allocated as required.  The    first entry of each chunk is reserved
  458. as a link to the next chunk (or    NULL in    the last chunk)    - this makes
  459. it easy    to find    all the    chunks to free them when we're finished.  All
  460. symbol table entries are stored    in pass    1.  During pass    2, cross-reference
  461. table entries are built    in the same group of chunks, immediately following
  462. the last symbol    table entry.  Additional chunks    will continue to be
  463. linked in if necessary.
  464.  
  465.      Symbol names and macro text are stored in another series of linked
  466. chunks.     These chunks consist of a link    pointer    followed by strings
  467. (terminated by nulls) laid end to end.    Symbols    are independent    entries,
  468. linked from the    corresponding symbol table entry.  Macros are stored as
  469. consecutive strings, one per line - the    end of the macro is indicated by
  470. an ENDM    statement.  If a macro spans two chunks, the last line in the
  471. original chunk is followed by a    newline    character to indicate that the
  472. macro is continued in the next chunk.
  473.  
  474.      Relocation    information is built during pass 2 in yet another series
  475. of linked chunks.  If more than    one chunk is needed to hold one    section's
  476. relocation information,    all additional chunks are released at the end of
  477. the section.
  478.  
  479.      The secondary heap    is built from both ends, and it    grows and shrinks
  480. according to how many macros and INCLUDE files are currently open.  At
  481. all times there    will be    at least one entry on the heap,    for the    original
  482. source code file.  The expression parser also uses the secondary heap to
  483. store its working stacks - this    space is freed as soon as an expression
  484. has been evaluated.
  485.      The bottom    of the heap holds the names of the source code file and
  486. any macro or INCLUDE files that    are currently open.  The full path is
  487. given.    A null string is stored    for user macros.  Macro    arguments are
  488. stored by additional strings, one for each argument in the macro call line.
  489. All strings are    stored in minimum space, similar to the    labels and user
  490. macro text on the primary heap.     File names are    pointed    to by the fixed
  491. table entries (see below) - macro arguments are    accessed by stepping past
  492. the macro name to the desired argument,    unless NARG would be exceeded.
  493.      The fixed portion of the heap is built down from the top.    Each entry
  494. occupies 16 bytes.  Enough information is stored to return to the proper
  495. position in the    outer file once    the current macro or INCLUDE file has been
  496. completely processed.
  497.      The diagram below illustrates the layout of the secondary heap.
  498.  
  499.     Heap2 +    maxheap2 ----------->  ___________________________
  500.                       |                  |
  501.                       |      Input    file table      |
  502.     struct InFCtl *InF ---------> |___________________________|
  503.                       |                  |
  504.                       |      Parser operator stack      |
  505.     struct OpStack *Ops --------> |___________________________|
  506.                       |                  |
  507.                       |      (unused space)      |
  508.     struct TermStack *Term -----> |___________________________|
  509.                       |                  |
  510.                       |      Parser term stack      |
  511.     char *NextFNS --------------> |___________________________|
  512.                       |                  |
  513.                       |      Input    file name stack      |
  514.     char *Heap2 ----------------> |___________________________|
  515.  
  516.      The "high-water mark" for NextFNS is stored in char *High2,
  517. and the    "low-water mark" (to stretch a metaphor) for InF is stored
  518. in struct InFCtl *LowInF.  These figures are used only to determine
  519. the maximum heap usage.
  520.  
  521.  
  522. AND FINALLY...
  523.  
  524.      Please send me any    bug reports, flames, etc.  I can be reached
  525. on Mind    Link (604/533-2312), at    any Panorama (PAcific NORthwest    AMiga
  526. Association) meeting, or via Jeff Lydiatt or Larry Phillips.
  527. (I don't have the time or money to live on Usenet or CompuServe, etc.)
  528.  
  529.                 Charlie    Gibbs
  530.                 2121 Rindall Avenue
  531.                 Port Coquitlam,    B.C.  V3C 1T9
  532.